package upm.pb4agent.team2;

import jade.content.AgentAction;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec.CodecException;
import jade.content.onto.OntologyException;
import jade.content.onto.UngroundedException;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.SimpleBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import upm.pb4agent.ontology.Dock;
import upm.pb4agent.ontology.DockDesignation;
import upm.pb4agent.ontology.RaceFinished;
import upm.pb4agent.ontology.Registration;
import upm.pb4agent.ontology.RegistrationForm;
import upm.pb4agent.ontology.SubscribeReferee;
import upm.pb4agent.ontology.TeamID;
import upm.pb4agent.team2.internalOntology.HasRaceFinished;

/**
 * TODO: Class description
 * 
 * @version 1.0
 * @author AlejandroB
 */
public class Manager extends Team2BaseAgent 
{
	// -------------------------------------------
	// -------------- PROPERTIES -----------------
	// -------------------------------------------
	
	private static final long serialVersionUID = 8944496533249210444L;
	
	private String rower21Name = Constants.ROWER21NAME;
	private String rower22Name = Constants.ROWER22NAME;
	private String rower23Name = Constants.ROWER23NAME;
	private String rower24Name = Constants.ROWER24NAME;
	
	private String rower21Dock = Constants.DOCK_A_ID;
	private String rower22Dock = Constants.DOCK_B_ID;
	private String rower23Dock = Constants.DOCK_C_ID;
	private String rower24Dock = Constants.DOCK_D_ID;

	private AID rower21ID;
	private AID rower22ID;
	private AID rower23ID;
	private AID rower24ID;

	private AID registrationDeskAID;

	private boolean raceEnded = false;
	
	// -------------------------------------------
	// --------------- METHODS -------------------
	// -------------------------------------------

	protected void setup() 
	{
		super.setup();
		
		addBehaviour(new CreateInitialRowers(this));
		addBehaviour(new RegisterInitialRowers(this));
		addBehaviour(new MessageListener(this));
		addBehaviour(new SubscribeToReferee(this));
	}
	
	private DockDesignation getDockDesignation(String dockName, AID rowerAID)
	{
		Dock dock = new Dock();
		dock.setName(dockName);
		
		DockDesignation dockDesignation = new DockDesignation();
		dockDesignation.setDock(dock);
		dockDesignation.setRowerID(rowerAID);
		
		return dockDesignation;
	}
		
	// -------------------------------------------
	// --------------- CLASSES -------------------
	// -------------------------------------------

	class CreateInitialRowers extends SimpleBehaviour 
	{

		private static final long serialVersionUID = -3120368223362591180L;

		public CreateInitialRowers(Agent agent) 
		{
			super(agent);
		}

		@Override
		public void action() 
		{
			// Create the initial 4 rowers
			rower21ID = createAndStartAgent(rower21Name, "upm.pb4agent.team2.Rower", new AID[] { myAgent.getAID() });
			rower22ID = createAndStartAgent(rower22Name, "upm.pb4agent.team2.Rower", new AID[] { myAgent.getAID() });
			rower23ID = createAndStartAgent(rower23Name, "upm.pb4agent.team2.Rower", new AID[] { myAgent.getAID() });
			rower24ID = createAndStartAgent(rower24Name, "upm.pb4agent.team2.Rower", new AID[] { myAgent.getAID() });
		}

		@Override
		public boolean done() 
		{
			return true;
		}
	}
	
	class SubscribeToReferee extends SimpleBehaviour 
	{

		private static final long serialVersionUID = -7143393353855383869L;
		private Boolean subscriptionSent = false;

		public SubscribeToReferee(Agent agent) 
		{
			super(agent);
		}

		@Override
		public void action() 
		{
			AID receiverAID = findAgentOnDF(myAgent, Constants.REFEREE);
			
			if (receiverAID != null)
			{
				sendSubscription(receiverAID);
			}
		}
		
		private void sendSubscription(AID receiverAID)
		{
			printOut("sending subscription request to referee...");
			
			SubscribeReferee subscribeReferee = new SubscribeReferee();
			Action action = new Action(receiverAID, subscribeReferee);
			
			sendMessage(receiverAID, ACLMessage.SUBSCRIBE, action, SubscribeReferee.class.getSimpleName().toString());
			
			subscriptionSent = true;
		}

		@Override
		public boolean done() 
		{
			return subscriptionSent;
		}
	}

	class RegisterInitialRowers extends SimpleBehaviour 
	{

		private static final long serialVersionUID = 4453493078898773165L;
		
		private boolean registrationSent = false;

		public RegisterInitialRowers(Agent agent) 
		{
			super(agent);
		}

		@Override
		public void action() 
		{
			TeamID teamID = new TeamID();
			teamID.setValue("2");

			Registration registration = new Registration();
			RegistrationForm registrationForm = new RegistrationForm();
			registrationForm.setTeamID(teamID);
			
			registrationForm.addDockDesignation(getDockDesignation(rower21Dock, rower21ID));
			registrationForm.addDockDesignation(getDockDesignation(rower22Dock, rower22ID));
			registrationForm.addDockDesignation(getDockDesignation(rower23Dock, rower23ID));
			registrationForm.addDockDesignation(getDockDesignation(rower24Dock, rower24ID));
			
			registration.setRegistrationForm(registrationForm);

			registrationDeskAID = findAgentOnDF(myAgent, Constants.REGISTRATION_DESK);
			
			if(registrationDeskAID != null)
			{
				sendMessage(registrationDeskAID, ACLMessage.REQUEST, new Action(registrationDeskAID, registration), Registration.class.getSimpleName().toString());
				registrationSent = true;
			}
		}

		@Override
		public boolean done() 
		{
			return registrationSent;
		}
	}

	class MessageListener extends SimpleBehaviour 
	{

		private static final long serialVersionUID = -7022932491687175246L;
		
		//private boolean registrationSuccessful = false;

		public MessageListener(Agent agent) 
		{
			super(agent);
		}

		@Override
		public void action() 
		{
			ACLMessage aclMessage = receive(MessageTemplate.and(MessageTemplate.MatchLanguage(codec.getName()), MessageTemplate.or(MessageTemplate.MatchOntology(ontology.getName()), MessageTemplate.MatchOntology(internalOntology.getName()))));

			printReceivedProtocol(aclMessage);
			
			if (aclMessage != null) 
			{
				if (aclMessage.getPerformative() == ACLMessage.INFORM) 
				{
					try
					{
						ContentElement contentElement = null;
						try
						{
							contentElement = getContentManager().extractContent(aclMessage);
						}
						catch (CodecException e) 
						{
							if (aclMessage.getSender().equals(registrationDeskAID))
							{
								printOut("Team 2 Registered properly.");
							}
							else
							{
								printOut("Empty message received from "+aclMessage.getSender().getLocalName());
								e.printStackTrace();
							}
						} 
						
						if (contentElement instanceof AgentAction)
						{
							Action action = (Action) contentElement;
							Concept concept = action.getAction();
							
							if (concept instanceof RaceFinished)
							{
								if(((RaceFinished)concept).getBoatAID().getLocalName().endsWith("2"))
								{
									raceEnded = true;
									printOut(" <<< !!!! FINISHED RACE IN POSITION # "+((RaceFinished)concept).getPosition() +" !!!! >>>");
								}
							}	
						}
					} 
					catch (UngroundedException e) 
					{
						e.printStackTrace();
					} 
					catch (OntologyException e) 
					{
						e.printStackTrace();
					}
				} 
				else if (aclMessage.getPerformative() == ACLMessage.REQUEST) 
				{
					try 
					{
						ContentElement contentElement = null;
						contentElement = getContentManager().extractContent(aclMessage);
						
						if (contentElement instanceof AgentAction)
						{
							Action action = (Action) contentElement;
							Concept concept = action.getAction();
							
							if (concept instanceof HasRaceFinished)
							{
								HasRaceFinished hasRaceFinished = new HasRaceFinished();
								hasRaceFinished.setHasFinished(raceEnded);
								sendInternalMessage(aclMessage.getSender(), ACLMessage.INFORM, new Action(aclMessage.getSender(), hasRaceFinished), HasRaceFinished.class.getSimpleName().toString());
							}
						}
					}
					catch (CodecException e) 
					{
						e.printStackTrace();
					} 
					catch (OntologyException oe) 
					{
						oe.printStackTrace();
					}
				}
				else if (aclMessage.getPerformative() == ACLMessage.REFUSE || aclMessage.getPerformative() == ACLMessage.NOT_UNDERSTOOD) 
				{
					String msg = "NOT_UNDERSTOOD";
					if (aclMessage.getPerformative() == ACLMessage.REFUSE)
					{
						msg = "REFUSE";
					}
					// Message format is wrong
					// Destroy the rowers
					destroyAgentsByName(rower21Name, rower22Name, rower23Name, rower24Name);
					
					printOut("Team 2 NOT registered, received "+msg+" response from RegistrationDesk.");
				}
			} 
			else 
			{
				// No message yet
				block();
			}
		}

		@Override
		public boolean done() 
		{
			return false;
		}

	}

}
